<!DOCTYPE html>
<html>
<!-- 
	1、二值化 需要高分辨率的图片，二值化精度高，位深度导致彩色图片过大

	2、dpi切换（前端目前还没有找到方法更改dpi）
	3、分辨率切换，考虑提供常用的分辨率（解决设备拍照画面不全的问题）

	4、切换视频源的弹窗确认操作，名称无法显示（是否支持 自定义）
 -->
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<!-- 暂时不用 -->
	<!-- <script src="ocrad.js"></script> -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/camanjs/4.1.2/caman.full.min.js">
	</script>
	<title>摄像头拍照</title>
</head>

<body>
	<div>
		<video id="video" width="800" height="600" controls="">
		</video>
	</div>
	<br />
	<div>
		<input type="button" title="开启摄像头" value="拍照识别" id="capture" />
		<input type="button" title="1" value="切视频源" id="changeV" />
		<select name="" id="changDpi">
			<option value="1600,1200">标清</option>
			<option value="2400,1800">高清</option>
		</select>
		<select name="" id="videoSources">
		</select>
		<input type="button" id="save" type="button" value="下载图片" />
		<input id="upFile" type="file" accept="image/PNG" value="上传图片" name="file" />
		<input type="button" id="clearImg" type="button" value="清除采集项" />
		<input type="button" id="grayScale" type="button" value="灰度" />
		<input type="button" id="black" type="button" value="二值化（黑白）" />
		<!-- <input type="button" id="color" type="button" value="原图（彩色）" />
		<input type="button" id="stop" type="button" value="停止拍摄" /> -->
	</div>
	<!-- 缩放 -->
	<canvas id="canvas"  width="800" height="600"></canvas>
	<canvas id="blackCanvas" width="680" height="420"></canvas>
	<script>
		window.onload = function () {
			//访问用户媒体设备的兼容方法
			function getUserMedia(constraints, success, error) {
				if (navigator.mediaDevices.getUserMedia) {
					//最新的标准API
					//alert("最新的标准API")
					navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
				} else if (navigator.webkitGetUserMedia) {
					//webkit核心浏览器
					//alert("webkit核心浏览器")
					navigator.webkitGetUserMedia(constraints, success, error)
				} else if (navigator.mozGetUserMedia) {
					//firfox浏览器
					//alert("firfox浏览器")
					navigator.mozGetUserMedia(constraints, success, error);
				} else if (navigator.getUserMedia) {
					//旧版API
					//alert("旧版API")
					navigator.getUserMedia(constraints, success, error);
				}
			}
			//获取页面对象
			let video = document.getElementById('video');
			let canvas = document.getElementById('canvas');
			let context = canvas.getContext('2d');
			let model = document.getElementById('modelSet');

			let imageWidth =1600;
			let imageHeight = 1200;
			let scaleRate = 2;
			//成功加载设备，播放流文件
			function success(stream) {
				//兼容webkit核心浏览器
				let CompatibleURL = window.URL || window.webkitURL;
				//将视频流设置为video元素的源
				//video.src = CompatibleURL.createObjectURL(stream);
				console.log(video);
				console.log(stream)
				video.srcObject = stream;
				video.play();
			}
			//出现错误提示
			function error(error) {
				console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
			}			
			if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator
				.mozGetUserMedia) {
				if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
					console.log("enumerateDevices() not supported.");
					return;
				}
				// 列出摄像头和麦克风
				var exArray = [];
				var checkIndex;
				//cyn mark
				var select = document.getElementById("select");
				//当前设备支持的分辨率
				let videoSourcesCount = 1;
				navigator.mediaDevices.enumerateDevices().then(function (devices) {
					devices.forEach(function (device) {
						console.log(device.kind + ": " + device.label +
							" id = " + device.deviceId);
						if (device.kind == "videoinput") {
							//alert(device.label.toString());
							exArray.push(device.deviceId);
							//下拉框添加设备列表
							var  videoSources =  document.getElementById("videoSources");
							var option=document.createElement("option");
							option.value= device.deviceId;
							var node=document.createTextNode("设备" + videoSourcesCount  + device.label+" ID:"+device.deviceId.substr(0,6));
							option.appendChild(node);
							videoSources.appendChild(option);
							videoSourcesCount++;
						}					
					});
					checkIndex = exArray.keys();
					var mediaOpts = {
						video: {
							// deviceId: {
							// 	exact: exArray[0]
							// },
							width: imageWidth, 
							height: imageHeight
						}
					};
					//调用用户媒体设备, 访问摄像头
					getUserMedia(mediaOpts, success, error);
				})
					.catch(function (err) {
						console.log(err.name + ": " + err.message);
					});
			} else {
				alert('不支持访问用户媒体');
			}
			var img = new Image();			
			//拍照
			document.getElementById('capture').addEventListener('click', function () {
				canvas.width = imageWidth;
				canvas.height = imageHeight;
				context.drawImage(video, 0, 0, imageWidth, imageHeight);
				// canvas转为blob并上传
				canvas.toBlob(function (blob) {
					console.log("blob");
					console.log(blob)
				// // 图片ajax上传
				// var xhr = new XMLHttpRequest();
				// // 开始上传
				// xhr.open("POST", 'upload.php', true);
				// xhr.send(blob);    
				});
			
				var scale = ((video.width* video.height)/(imageWidth*imageHeight) ) * scaleRate

				//console.log(video.width+" "+video.height+" "+imageWidth+" "+imageHeight);
				//设置缩放
				canvas.style="transform: scale("+scale+");transform-origin: 0 0;";
				//canvas.style="transform: scale(0.5);transform-origin: 0 0;";

			});
			//切换视频源
			document.getElementById('changeV').addEventListener('click', function () {
				var arrayIndex = checkIndex.next().value;
				if (arrayIndex == undefined) {
					checkIndex = exArray.keys();
				}
				var mediaOptsT = {
					video: {
						deviceId: {
							exact: exArray[arrayIndex]
						},
					}
				};
				getUserMedia(mediaOptsT, success, error);
			});
			//选择视频源
			document.getElementById('videoSources').addEventListener('change', function () {
				changeDpiSources ();
			});
			//切换分辨率
			document.getElementById('changDpi').addEventListener('change', function () {
				//切分辨率，视频源需要重新加载
				changeDpiSources ();
			});
			
			function changeDpiSources (){
				//分辨率
				var  dpi =  document.getElementById("changDpi");
				//视频源
				var  videoSources =  document.getElementById("videoSources");										
				var changeWidth = dpi.value.split(",")[0];
				var changeHeight = dpi.value.split(",")[1];
				if(changeWidth=="1600"){
					scaleRate =2;
				}else if(changeWidth=="2400"){
					scaleRate =3;
				}
				imageHeight = changeHeight;
				imageWidth = changeWidth;
				var mediaOptsT = {
					video: {
						width:imageWidth, 
						height: imageHeight,
						deviceId: videoSources.value					
					}
				};
				console.log(mediaOptsT);
				getUserMedia(mediaOptsT, success, error);
			}
			
			//文件保存下载
			document.getElementById('save').addEventListener('click',function (){
				//上传时判断是否拍照
				var emptyCV = document.createElement('canvas');//系统获取一个空canvas对象
				emptyCV.width = canvas.width;
				emptyCV.height = canvas.height;
				if (canvas.toDataURL() == emptyCV.toDataURL()) {
					alert("未采集！无法下载！");
					return;
				}
				//保存图片格式
				var type = 'jpg';
				var _fixType = function(type) {
					type = type.toLowerCase().replace(/jpg/i, 'jpeg');
					var r = type.match(/png|jpeg|bmp|gif/)[0];
					return 'image/' + r;
				}
				//获取canvas标签里的图片内容	
				var dataURL  = document.getElementById('canvas').toDataURL("image/jpeg",0.3);				
				//dataURL  = dataURL.replace(_fixType(type),'image/octet-stream');			
				var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
				save_link.href = dataURL;
				save_link.download = (new Date()).getTime() + '.' + type;;		
				//触发下载
				var event = document.createEvent('MouseEvents');
				event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
				save_link.dispatchEvent(event);
			});
			//32位转16位
			function  bit32to16(chunk) {
				const b16 = new Int16Array(chunk.byteLength / 4);
				const dv = new DataView(chunk.buffer);
				for (let i = 0, offset = 0; offset < chunk.byteLength; i++, offset += 4){
					const v = dv.getFloat32(offset, true);
					b16[i] = v > 0 ? v * 32767 : v * 32768;
				}
				return b16.buffer
			}
			//清除已拍图片
			document.getElementById('clearImg').addEventListener('click',function ()  {  
				var c=document.getElementById("canvas");  
				var cxt=c.getContext("2d");  
				cxt.clearRect(0,0,c.width,c.height);  
			})			
	        //停止
			
			//采集列表
			var ScanImageListJson = {
									"ScanImageList": {
										"count": "4",
										"branchNo": "1",
										"custCode": "100267",
										"businessArchId": "201907120000000002",
										"currentItemIndex": "0",
										"TImage": [
										{
											"index": "1",
											"archImageNo": "03",
											"imageName": "休眠账户激活申请表",
											"imageSet": "2",
											"imageDpi": "0",
											"imageType": "1",
											"haveScan": "1",
											"fileSize": "112",
											"lowFileSize": "111",
											"filePath": " ",
											"importLocalFlag": "0",
											"datewaterFlag": "0",
											"pageNum": "1"
										},
										{
											"index": "2",
											"archImageNo": "06",
											"imageName": "合并证券账户申请表",
											"imageSet": "1",
											"imageDpi": "100",
											"imageType": "1",
											"haveScan": "1",
											"fileSize": "5000",
											"lowFileSize": "0",
											"filePath": "http://10.20.27.95/group1/M00/00/33/oYYBAF0n6YaEaIlAAAAAAAAAAAA808.tif",
											"importLocalFlag": "0",
											"datewaterFlag": "1",
											"pageNum": "3"
										},
										{
											"index": "3",
											"archImageNo": "05",
											"imageName": "注销证券账户申请表",
											"imageSet": "2",
											"imageDpi": "200",
											"imageType": "1",
											"haveScan": "1",
											"fileSize": "1000",
											"lowFileSize": "0",
											"filePath": "http://10.20.27.95/group1/M00/00/33/ooYBAF0n6YaEKA01AAAAAAAAAAA490.tif",
											"importLocalFlag": "0",
											"datewaterFlag": "0",
											"pageNum": "1"
										},
										{
											"index": "0",
											"archImageNo": "9A",
											"imageName": "证券账户业务申请表（适用于办理证券账户查询、变更、休眠激活、注销、网络服务业务）",
											"imageSet": "0",
											"imageDpi": "0",
											"imageType": "6",
											"haveScan": "1",
											"fileSize": "0",
											"lowFileSize": "0",
											"filePath": "http://10.20.27.95/group1/M00/00/33/oYYBAF0n6miENdIEAAAAAAAAAAA403.pdf",
											"importLocalFlag": "0",
											"datewaterFlag": "0",
											"pageNum": "1"
										}
										]
									}
								};
			// var resultS = JSON.parse(ScanImageListJson);

			//原图
			let colorImageCv= canvas;
			//灰度化
			function getGrayScaleImage(){
				//彩色图像灰度化
				//取得图像数据
				var canvasData=document.getElementById("canvas");  
				var cxt=canvasData.getContext("2d"); 
				var canvasData = cxt.getImageData(0, 0, canvas.width, canvas.height);
				//这个循环是取得图像的每一个点，在计算灰度后将灰度设置给原图像
				for (var x = 0; x < canvasData.width; x++) {
					//alert("x="+x);
					for (var y = 0; y < canvasData.height; y++) {
						//alert("y="+y);
						// Index of the pixel in the array
						var idx = (x + y * canvas.width) * 4;
						// The RGB values
						var r = canvasData.data[idx + 0];
						var g = canvasData.data[idx + 1];
						var b = canvasData.data[idx + 2];
						//更新图像数据
						var gray = CalculateGrayValue(r , g , b);
						canvasData.data[idx + 0] = gray;
						canvasData.data[idx + 1] = gray;
						canvasData.data[idx + 2] = gray;
					}
				}
				cxt.putImageData(canvasData, 0, 0);
				//计算图像的灰度值,公式为：Gray = R*0.299 + G*0.587 + B*0.114
				function CalculateGrayValue(rValue,gValue,bValue){
					return parseInt(rValue * 0.299 + gValue * 0.587 + bValue * 0.114);
				}
				return [canvasData,cxt];
			}
			//添加点击事件
			document.getElementById('grayScale').addEventListener('click',function () {
				getGrayScaleImage();
			})
		
			//二值化
			//一维OTSU图像处理算法
			function OTSUAlgorithm(){
				var m_pFstdHistogram = new Array();//表示灰度值的分布点概率
				var m_pFGrayAccu = new Array();//其中每一个值等于m_pFstdHistogram中从0到当前下标值的和
				var m_pFGrayAve = new Array();//其中每一值等于m_pFstdHistogram中从0到当前指定下标值*对应的下标之和
				var m_pAverage=0;//值为m_pFstdHistogram【256】中每一点的分布概率*当前下标之和
				var m_pHistogram = new Array();//灰度直方图
				var i,j;
				var temp=0,fMax=0;//定义一个临时变量和一个最大类间方差的值
				var nThresh = 0;//最优阀值
				//获取灰度图像的信息			//获取图像的灰度图像的信息
				function GetGrayImageInfo(){
					return getGrayScaleImage();
				}
				var imageInfo = GetGrayImageInfo();
				if(imageInfo == null){
					window.alert("图像还没有转化为灰度图像！");
					return;
				}
				//初始化各项参数
				for(i=0; i<256; i++){
					m_pFstdHistogram[i] = 0;
					m_pFGrayAccu[i] = 0;
					m_pFGrayAve[i] = 0;
					m_pHistogram[i] = 0;
				}
				//获取图像信息
				var canvasData = imageInfo[0];
				//获取图像的像素
				var pixels = canvasData.data;
				//下面统计图像的灰度分布信息
				for(i=0; i<pixels.length; i+=4){
					//获取r的像素值，因为灰度图像，r=g=b，所以取第一个即可
					var r = pixels[i];
					m_pHistogram[r]++;
				}
				//下面计算每一个灰度点在图像中出现的概率
				var size = canvasData.width * canvasData.height;
				for(i=0; i<256; i++){
					m_pFstdHistogram[i] = m_pHistogram[i] / size;
				}
				//下面开始计算m_pFGrayAccu和m_pFGrayAve和m_pAverage的值
				for(i=0; i<256; i++){
					for(j=0; j<=i; j++){
						//计算m_pFGaryAccu[256]
						m_pFGrayAccu[i] += m_pFstdHistogram[j];
						//计算m_pFGrayAve[256]
						m_pFGrayAve[i] += j * m_pFstdHistogram[j];
					}
					//计算平均值
					m_pAverage += i * m_pFstdHistogram[i];
				}
				//下面开始就算OSTU的值，从0-255个值中分别计算ostu并寻找出最大值作为分割阀值
				for (i = 0 ; i < 256 ; i++){
					temp = (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i]) 
						* (m_pAverage * m_pFGrayAccu[i] - m_pFGrayAve[i]) 
						/ (m_pFGrayAccu[i] * (1 - m_pFGrayAccu[i]));
					if (temp > fMax){
						fMax = temp;
						nThresh = i;
					}
				}
				//下面执行二值化过程 
				for(i=0; i<canvasData.width; i++){
					for(j=0; j<canvasData.height; j++){
						//取得每一点的位置
						var ids = (i + j*canvasData.width)*4;
						//取得像素的R分量的值
						var r = canvasData.data[ids];
						//与阀值进行比较，如果小于阀值，那么将改点置为0，否则置为255
						var gray = r>nThresh?255:0;
						canvasData.data[ids+0] = gray;
						canvasData.data[ids+1] = gray;
						canvasData.data[ids+2] = gray;
					}
				}
				//显示二值化图像
				var newImage = document.getElementById('canvas').getContext('2d');
				newImage.putImageData(canvasData,0,0);
			}  
			document.getElementById('black').addEventListener('click',function () {
				OTSUAlgorithm();
			})
		}
	</script>
</body>

</html>